package com.wixct.common;

import org.apache.hc.client5.http.ConnectionKeepAliveStrategy;
import org.apache.hc.client5.http.config.ConnectionConfig;
import org.apache.hc.client5.http.config.RequestConfig;
import org.apache.hc.client5.http.impl.DefaultHttpRequestRetryStrategy;
import org.apache.hc.client5.http.impl.classic.CloseableHttpClient;
import org.apache.hc.client5.http.impl.classic.HttpClientBuilder;
import org.apache.hc.client5.http.impl.classic.HttpClients;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManager;
import org.apache.hc.client5.http.impl.io.PoolingHttpClientConnectionManagerBuilder;
import org.apache.hc.core5.http.HeaderElement;
import org.apache.hc.core5.http.HeaderElements;
import org.apache.hc.core5.http.HttpResponse;
import org.apache.hc.core5.http.io.SocketConfig;
import org.apache.hc.core5.http.message.BasicHeaderElementIterator;
import org.apache.hc.core5.http.protocol.HttpContext;
import org.apache.hc.core5.util.TimeValue;
import org.apache.hc.core5.util.Timeout;


/**
 * @author Administrator
 * {@code @date} 2024/11/16 18:20
 */
public class HttpClient5Utils {

    final private static long CONNECTION_TIMEOUT=2; //HTTP链接超时时间，soconds
    final private static long SOCKET_TIMEOUT=2; //SOCKET链接超时时间，soconds
    final private static long KEEP_LIVE_TIMEOUT=120; //keep-live链接保持时间，soconds
    final private static long REQUEST_TIMEOUT=3; //请求超时时间，soconds
    final private static long RESPONSE_TIMEOUT =2; //返回接收超时时间，soconds
    final private static int MAX_THREADS = 500; //最大链接时间，threads
    final private static int THREADS_PRE_ROUTE = 100; //每个路由的最大threads
    final private static int RETRY_TIMES = 2; //重试次数
    final private static int RETRY_INTERVAL_TIME = 2; //没次重试间隔时间，seconds

    private static ConnectionKeepAliveStrategy strategy; //策略
    private static PoolingHttpClientConnectionManager connectionManager;//链接池
    private static volatile CloseableHttpClient httpClient; //httpClient
    private static RequestConfig requestConfig;

    /**
     * 设置connection连接池
     * @return 连接池
     */
    private static PoolingHttpClientConnectionManager getConnectionManager(){
        if(connectionManager == null){

            //设置连接配置
            ConnectionConfig connectionConfig = ConnectionConfig.custom()
                    .setConnectTimeout(Timeout.ofSeconds(CONNECTION_TIMEOUT))
                    .setSocketTimeout(Timeout.ofSeconds(SOCKET_TIMEOUT))
                    .build();
            //设置socket链接配置
            SocketConfig socketConfig = SocketConfig.custom()
                    .setSoTimeout(Timeout.ofSeconds(SOCKET_TIMEOUT))
                    .build();
            connectionManager = PoolingHttpClientConnectionManagerBuilder.create().build();
            connectionManager.setDefaultConnectionConfig(connectionConfig);
            connectionManager.setDefaultSocketConfig(socketConfig);
            connectionManager.setMaxTotal(MAX_THREADS);//最大链接数
            connectionManager.setDefaultMaxPerRoute(THREADS_PRE_ROUTE); //最大并发连接数，限制每个路由的最大连接数，过小会阻塞
        }
        return connectionManager;
    }

    /**
     * 设置keep-live策略
     * @return 链接策略
     */
    private static ConnectionKeepAliveStrategy getStrategy(){
        if(strategy == null){
            strategy = new ConnectionKeepAliveStrategy() {
                @Override
                public TimeValue getKeepAliveDuration(HttpResponse response, HttpContext context) {
                    BasicHeaderElementIterator it = new BasicHeaderElementIterator
                            (response.headerIterator( HeaderElements.KEEP_ALIVE));
                    while (it.hasNext()) {
                        HeaderElement he = it.next();
                        String param = he.getName();
                        String value = he.getValue();
                        if (value != null && param.equalsIgnoreCase
                                ("timeout")) {
                            return TimeValue.ofSeconds(Long.parseLong(value));
                        }
                    }
                    return TimeValue.ofSeconds(KEEP_LIVE_TIMEOUT);
                }

            };
        }
        return strategy;
    }

    /**
     * 设置RequestConfig
     * @return  RequestConfig
     */
    private static RequestConfig getRequestConfig(){
        if(requestConfig == null){
            requestConfig=RequestConfig.custom()
                    .setConnectionRequestTimeout(Timeout.ofSeconds(REQUEST_TIMEOUT))
                    .setResponseTimeout(Timeout.ofSeconds(RESPONSE_TIMEOUT))
                    .setContentCompressionEnabled(true)//启用内容压缩
                    .build();
        }
        return requestConfig;
    }

    /**
     * 获取 HttpClientBuilder,用于配置restTemplate;
     * @return HttpClientBuilder
     */
    public static HttpClientBuilder getHttpClientBuilder(){
        return HttpClients.custom()
                .setConnectionManager(getConnectionManager())
                .setKeepAliveStrategy(getStrategy())
                .setDefaultRequestConfig(getRequestConfig())
                .setRetryStrategy(new DefaultHttpRequestRetryStrategy(RETRY_TIMES, TimeValue.ofSeconds(2)));
    }

    /**
     * 设置HttpClient，获取单例模式的httpclient
     * @return HttpClient
     */
    public static CloseableHttpClient getHttpClient() {
        if (httpClient == null) {
            synchronized (HttpClient5Utils.class) {
                if (httpClient == null) {
                    httpClient= HttpClients.custom()
                            .setConnectionManager(getConnectionManager())
                            .setKeepAliveStrategy(getStrategy())
                            .setDefaultRequestConfig(getRequestConfig())
                            .setRetryStrategy(new DefaultHttpRequestRetryStrategy(RETRY_TIMES, TimeValue.ofSeconds(RETRY_INTERVAL_TIME)))
                            .build();
                }
            }
        }
        return httpClient;
    }
}
